package com.iocup.keybastion.authorize.element;


import com.google.common.collect.Lists;
import com.iocup.keybastion.common.ConcurrentCyclicSequence;

import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

/**
 * @author xyjxust
 * @create 2022/3/2 11:16
 **/
public class InMemoryAuthElementStore implements AuthElementStore {

    private static final ConcurrentHashMap<String, ConcurrentCyclicSequence<AuthElement>> elementMap = new ConcurrentHashMap<>();

    @Override
    public AuthElementStore put(AuthElement element) {
        addElement(element.getCode(), element);
        return this;
    }

    private void addElement(String address, AuthElement actor) {
        Objects.requireNonNull(address, "address");


        ConcurrentCyclicSequence<AuthElement> handlers = new ConcurrentCyclicSequence<AuthElement>().add(actor);
        ConcurrentCyclicSequence<AuthElement> actualHandlers = elementMap.merge(
                address,
                handlers,
                (old, prev) -> {
                    AuthElement actor1 = prev.first();
                    if (!contain(old, actor1)) {
                        return old.add(prev.first());
                    }
                    return old;
                });
    }

    private boolean contain(ConcurrentCyclicSequence<AuthElement> sequence, AuthElement actor) {
        AtomicBoolean result = new AtomicBoolean(false);
        sequence.forEach(actor1 -> {
            if (actor1.hashCode() == actor.hashCode()) {
                result.set(true);
                return;
            }
        });
        return result.get();
    }

    @Override
    public List<AuthElement> get(String key) {
        ConcurrentCyclicSequence<AuthElement> c = elementMap.get(key);
        if (c == null) {
            return Lists.newArrayList();
        }
        return c.values();
    }

    @Override
    public List<AuthElement> getAll() {
        return elementMap.values().stream().map(ConcurrentCyclicSequence::values).flatMap(Collection::stream).collect(Collectors.toList());
    }

    @Override
    public void clear() {
        elementMap.clear();
    }
}
